﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;

namespace HDLogCenter.Infrastructure.Utils
{
    public static class DateTimeHelper
    {
        /// <summary>
        /// 将 DateTime 转换为整数格式（默认 yyyyMMdd）
        /// </summary>
        public static int ToInt(this DateTime dateTime, string format = "yyyyMMdd")
        {
            int.TryParse(dateTime.ToString(format, DateTimeFormatInfo.InvariantInfo), out int result);
            return result;
        }

        /// <summary>
        /// 转换为日期部分整数（yyyyMMdd）
        /// </summary>
        public static int ToDateInt(this DateTime dateTime) => dateTime.ToInt();

        /// <summary>
        /// 转换为时间部分整数（HHmmss）
        /// </summary>
        public static int ToTimeInt(this DateTime dateTime) => dateTime.ToInt("HHmmss");

        /// <summary>
        /// 将 yyyyMMdd 和 HHmmss 整数转换为 DateTime
        /// </summary>
        public static DateTime ToDateTime(int datePart, int timePart)
        {
            if (datePart < 19000101)
                return DateTime.MinValue;
            if (datePart > 99991231)
                return DateTime.MaxValue;

            string dateStr = datePart.ToString("0000-00-00");
            string timeStr = timePart.ToString().PadLeft(6, '0').Insert(2, ":").Insert(5, ":");

            return DateTime.Parse($"{dateStr} {timeStr}", CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// 将整数（yyyyMMdd）转换为 DateTime
        /// </summary>
        public static DateTime ToDateTime(this int intDate, string format = "yyyyMMdd")
        {
            var provider = new CultureInfo("zh-CN", true);
            return DateTime.ParseExact(intDate.ToString(), format, provider);
        }

        /// <summary>
        /// 尝试将整数转换为 DateTime（yyyyMMdd）
        /// </summary>
        public static bool TryToDate(this int intDate, out DateTime dateOut)
        {
            dateOut = new DateTime(1900, 1, 1);
            if (intDate / 10000000 == 0)
                return false;

            string dateStr = intDate.ToString("0000-00-00");
            return DateTime.TryParse(dateStr, out dateOut);
        }

        /// <summary>
        /// 安全转换为 DateTime，失败返回 MinValue
        /// </summary>
        public static DateTime ToDate(this int intDate)
        {
            try
            {
                return intDate.ToDateTime();
            }
            catch
            {
                return DateTime.MinValue;
            }
        }

        public static DateTime GetFirstDayOfThisYear(this DateTime date) =>
            new DateTime(date.Year, 1, 1);

        public static DateTime GetFirstDayOfThisQuarter(this DateTime date) =>
            new DateTime(date.Year, ((date.Month - 1) / 3) * 3 + 1, 1);

        public static DateTime GetFirstDayOfThisMonth(this DateTime date) =>
            new DateTime(date.Year, date.Month, 1);

        public static DateTime GetFirstDayOfThisWeek(this DateTime date) =>
            date.DayOfWeek == DayOfWeek.Sunday
                ? date.Date
                : date.Date.AddDays(-(int)date.DayOfWeek);

        /// <summary>
        /// 获取该日期是一年中的第几周
        /// </summary>
        public static int WeekOfYear(this DateTime date)
        {
            DateTime firstDay = new DateTime(date.Year, 1, 1);
            return ((date - firstDay).Days + (int)firstDay.DayOfWeek) / 7 + 1;
        }

        /// <summary>
        /// 转换为 Unix 时间戳（秒或毫秒）
        /// </summary>
        public static long ToUnixTime(this DateTime dt, bool milliseconds = false)
        {
            var epoch = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1), TimeZoneInfo.Local);
            return milliseconds
                ? (long)(dt - epoch).TotalMilliseconds
                : (long)(dt - epoch).TotalSeconds;
        }

        /// <summary>
        /// 根据 Unix 时间戳恢复 DateTime（秒或毫秒）
        /// </summary>
        public static DateTime ConvertTimeByUnix(this long unixTime, bool milliseconds = false)
        {
            var epoch = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1), TimeZoneInfo.Local);
            return milliseconds
                ? epoch.AddMilliseconds(unixTime)
                : epoch.AddSeconds(unixTime);
        }

        /// <summary>
        /// 两个时间差值（按指定粒度）
        /// </summary>
        public static long DateDiff(this DateTime endDate, DateTime startDate, DateInterval interval)
        {
            TimeSpan span = endDate - startDate;
            long result = 0;
            switch (interval)
            {
                case DateInterval.Day:
                    result = span.Days;
                    break;
                case DateInterval.Hour:
                    result = (long)span.TotalHours;
                    break;
                case DateInterval.Minute:
                    result = (long)span.TotalMinutes;
                    break;
                case DateInterval.Month:
                    result = span.Days / 30;
                    break;
                case DateInterval.Quarter:
                    result = span.Days / 90;
                    break;
                case DateInterval.Second:
                    result = (long)span.TotalSeconds;
                    break;
                case DateInterval.Week:
                    result = span.Days / 7;
                    break;
                case DateInterval.Year:
                    result = span.Days / 365;
                    break;
                default:
                    result = 0;
                    break;
            }
            return result;
        }

        public enum DateInterval
        {
            Day,
            Hour,
            Minute,
            Month,
            Quarter,
            Second,
            Week,
            Year
        }
    }
}

